package org.dromara.assets.biz;

import cn.hutool.core.util.HexUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.crypto.Mode;
import cn.hutool.crypto.Padding;
import cn.hutool.crypto.symmetric.DES;
import cn.hutool.json.JSONUtil;
import com.binance.api.client.BinanceApiClientFactory;
import com.binance.api.client.BinanceApiRestClient;
import com.binance.api.client.domain.account.Order;
import com.binance.api.client.domain.account.Trade;
import com.binance.api.client.domain.account.request.AllOrdersRequest;
import com.binance.connector.client.SpotClient;
import com.binance.connector.client.impl.SpotClientImpl;
import com.binance.connector.client.utils.ProxyAuth;
import org.dromara.assets.config.ConfigReader;
import org.dromara.assets.domain.AssetsAccount;
import org.dromara.assets.domain.AssetsTokenpair;
import org.dromara.assets.domain.bo.AssetsTokenpairBo;
import org.dromara.assets.domain.vo.AssetsTokenpairVo;
import org.dromara.assets.service.IAssetsAccountService;
import org.dromara.assets.service.IAssetsTokenpairService;
import org.dromara.assets.service.IAssetsTradeRecordService;
import org.dromara.assets.util.DataCache;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.encrypt.utils.EncryptUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.Collectors;

@Component("binanceBiz")
@Slf4j
public class BinanceBiz {

    @Autowired
    IAssetsTokenpairService assetsTokenpairService;

    @Autowired
    private IAssetsAccountService assetsAccountService;

    private final Map<Long, BinanceApiRestClient> clientMap = new HashMap<>();

    public static DataCache dataCache = new DataCache();
    @Autowired
    private AssetsTradeRecordServiceBiz assetsTradeRecordServiceBiz;

    public List<Order> getAllOrders(AssetsAccount account, String symbol) {
        BinanceApiRestClient client = getClient(account);
        List<Order> allOrders = client.getAllOrders(new AllOrdersRequest(symbol).limit(40));
        List<Order> allOrderAfterFilter = allOrders.stream().filter(order -> !dataCache.contains(symbol, order.getOrderId().toString())).collect(Collectors.toList());
        log.info("需要同步订单：symbol:{}, allOrderAfterFilter:{}", symbol, allOrderAfterFilter);
        return allOrderAfterFilter;
    }

    private BinanceApiRestClient getClient(AssetsAccount account) {
        BinanceApiRestClient client = clientMap.get(account.getId());
        if (client != null) {
            return client;
        }
        BinanceApiClientFactory factory = BinanceApiClientFactory.newInstance(account.getApiKey(), account.getApiSecret());
        client = factory.newRestClient();
        clientMap.put(account.getId(), client);
        return client;
    }

    public List<Trade> getTrades(String symbol, Long orderId) {
        Map<String, Object> parameters = new HashMap();
        parameters.put("symbol", symbol);
        parameters.put("orderId", orderId);
        //TODO
        String result = createSpotClient(null).createTrade().myTrades(parameters);
        List<Trade> resultList = JSONUtil.toList(result, Trade.class);
        log.info("trade结果：{}", resultList);
        return resultList;
    }


    public void syncTradeRecord(AssetsAccount account, List<Order> orders) {
        //List<Trade> myTrades = getMyTrades(symbol, apiKey, apiSecret);
        for (Order order : orders) {
            //#如果以市价卖出，在同步数据时接口返回的price为0，所以需要计算Price
            if (order.getPrice().equals("0")) {
                calcPrice(order);
            }
            boolean isNew = assetsTradeRecordServiceBiz.syncItem(order.getSymbol(), order, account.getId());
            //#更新手续费
            /***
             if (is_new or order[16]is None) && trade_record.getStatus().equals(OrderStatus.FILLED)){
             //#查询手续费
             Map fee_dict = new HashMap<>();
             temp_amount = 0;
             for (Trade trade : myTrades) {
             if (trade.getOrderId().equals(trade_record.getOrderId())) {
             String commissionAsset = trade.getCommissionAsset();
             amount = trade.getCommission();
             if (fee_dict.get(commissionAsset) != null) {
             fee_dict.put(commissionAsset, fee_dict[commissionAsset] + Decimal(amount));
             } else {
             fee_dict[commissionAsset] = Decimal(amount)
             temp_amount += Decimal(trade["qty"])
             }
             }
             }
             if (trade_record.getOrigQty().equals(temp_amount)) {
             //#保存数据
             //updateFee(order[0], fee_dict);

             }
             }
             **/

        }
    }

    /**
     * 计算价格
     */
    private void calcPrice(Order order) {
        BigDecimal dealAmount = new BigDecimal("0");
        BigDecimal dealQuantity = new BigDecimal("0");
        List<Trade> myTrades = getTrades(order.getSymbol(), order.getOrderId());
        for (Trade item : myTrades) {
            if (item.getOrderId().equals(order.getOrderId() + "")) {
                dealAmount = dealAmount.add(new BigDecimal(item.getQuoteQty()));
                dealQuantity = dealQuantity.add(new BigDecimal(item.getQty()));
                if (!dealQuantity.equals(new BigDecimal(order.getOrigQty()))) {
                    throw new RuntimeException("交易未完成");
                } else {
                    BigDecimal price = dealAmount.divide(dealQuantity);
                    order.setPrice(price.toString());
                }
            }
        }
    }

    public void syncTradeRecordBinance() {
        AssetsTokenpairBo assetsTokenpair = new AssetsTokenpairBo();
        assetsTokenpair.setPlatform(1L);
        assetsTokenpair.setStatus(1L);
        List<AssetsTokenpairVo> assetsTokenpairList = assetsTokenpairService.queryList(assetsTokenpair);
        List<AssetsAccount> assetsAccountList = assetsAccountService.selectAssetsAccountList4Binance();

        for (AssetsAccount account : assetsAccountList) {
            account.setApiSecret(desEncrypt(account.getApiSecret()));
            for (AssetsTokenpairVo item : assetsTokenpairList) {
                List<Order> orders = getAllOrders(account, item.getTokenPair());
                if (ObjectUtil.isEmpty(orders)) {
                    continue;
                }
                syncTradeRecord(account, orders);
            }
        }
    }
    static String key = ConfigReader.getConfig("Django", "encrypt_secret_pw");
    public static String desEncrypt(String s) {
        // 将密钥转换为字节数组
        byte[] secretKey = key.getBytes(StandardCharsets.UTF_8);
        // 初始化向量，这里使用与密钥相同的值
        byte[] iv = secretKey;

        // 创建 DES 对象，指定使用 CBC 模式和 PKCS5 填充
        DES des = new DES(Mode.CBC, Padding.PKCS5Padding, secretKey, iv);

        // 将十六进制字符串转换为字节数组
        byte[] encryptedBytes = HexUtil.decodeHex(s);

        // 执行解密操作
        byte[] decryptedBytes = des.decrypt(encryptedBytes);

        // 将解密后的字节数组转换为字符串
        return new String(decryptedBytes, StandardCharsets.UTF_8);
    }

    private SpotClient createSpotClient(AssetsAccount account) {
        SpotClient spotClient = new SpotClientImpl(account.getApiKey(), account.getApiSecret());
        Proxy proxyConn = new Proxy(Proxy.Type.SOCKS, new InetSocketAddress("127.0.0.1", 1081));
        ProxyAuth proxy = new ProxyAuth(proxyConn, null);
        spotClient.setProxy(proxy);
        return spotClient;
    }

}
